package com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetCategoryManagement;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetFixedStorage;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.req.SmsAssetFixedStorageBatchReq;
import com.xyht.sca_s.student_manage_system.modules.asset.mapper.SmsAssetFixedStorageMapper;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.entity.SmsAssetFixedDepreciationTask;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.entity.SmsAssetFixedDepreciationTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.entity.resp.SmsAssetFixedDepreciationTaskDetailResp;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.entity.resp.SmsAssetFixedDepreciationTaskResp;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.mapper.SmsAssetFixedDepreciationTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.mapper.SmsAssetFixedDepreciationTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.service.SmsAssetFixedDepreciationTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import com.xyht.sca_s.student_manage_system.modules.user.entity.resp.SmsSearchUserResp;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetStatusConstant.ASSET_STATUS_IN_STORAGE;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetStatusConstant.ASSET_STATUS_OUT;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.InStorageMethodConstant.IN_STORAGE_METHOD_FIXED_IMPORT;
import static com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.constant.CommonConstant.ASSET_DEFAULT_PAGE_SIZE;
import static com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.constant.TaskDetailReasonConstant.REASON_UPDATE_ERR;
import static com.xyht.sca_s.student_manage_system.modules.assetFixedDepreciation.constant.TaskStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_DONE;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_ERR;

/**
 * <p>
 * 资产折旧任务表 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2024-10-10
 */
@Service
public class SmsAssetFixedDepreciationTaskServiceImpl extends ServiceImpl<SmsAssetFixedDepreciationTaskMapper, SmsAssetFixedDepreciationTask> implements SmsAssetFixedDepreciationTaskService {
    @Resource
    private SmsAssetFixedDepreciationTaskMapper smsAssetFixedDepreciationTaskMapper;
    @Resource
    private SmsAssetFixedDepreciationTaskDetailMapper smsAssetFixedDepreciationTaskDetailMappers;
    @Resource
    private SmsAssetFixedStorageMapper smsAssetFixedStorageMapper;
    @Resource
    private CacheUtil cacheUtil;

    @Override
    @Async
    public Future<ResponseResult> updateAllAsset(String user_id) {
        //校验是否有进行中的任务
        int count = this.count(new LambdaQueryWrapper<SmsAssetFixedDepreciationTask>()
                .eq(SmsAssetFixedDepreciationTask::getTaskStatus, TASK_STATUS_DOING));
        if (count > 0) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.ASSET_DEPRECIATION_TASK_DOING));
        }

        SmsAssetFixedDepreciationTask smsAssetFixedDepreciationTask = new SmsAssetFixedDepreciationTask();
        smsAssetFixedDepreciationTask.setTaskStatus(TASK_STATUS_DOING);
        smsAssetFixedDepreciationTask.setCreateUserId(user_id);
        this.save(smsAssetFixedDepreciationTask);
        if (isNullOrEmpty(smsAssetFixedDepreciationTask.getId())) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }

        batchUpdateFixedStorage(smsAssetFixedDepreciationTask.getId(), user_id);
        return new AsyncResult<>(CommonResult.success());
    }

    @Resource
    PlatformTransactionManager transactionManager;

    private void batchUpdateFixedStorage(String task_id, String user_id) {
        int task_finish_status = TASK_STATUS_FINISH;
        //初始数据数量 排除已处置
        List<SmsAssetFixedStorage> initList = smsAssetFixedStorageMapper.selectList(new QueryWrapper<SmsAssetFixedStorage>()
                .select("id")
                .lambda()
                .ne(SmsAssetFixedStorage::getAssetStatus, ASSET_STATUS_OUT));
        if (initList.size() == 0) {
            SmsAssetFixedDepreciationTask smsImportTask = new SmsAssetFixedDepreciationTask();
            smsImportTask.setId(task_id);
            smsImportTask.setTaskStatus(task_finish_status);
            this.updateById(smsImportTask);
            return;
        }
        int pageMaxNum;
        int remainder = initList.size() % ASSET_DEFAULT_PAGE_SIZE;
        if (remainder == 0) {
            pageMaxNum = initList.size() / ASSET_DEFAULT_PAGE_SIZE;
        } else {
            double num = (double) initList.size() / ASSET_DEFAULT_PAGE_SIZE;
            pageMaxNum = (int) Math.ceil(num);
        }

        Date nowDate = new Date();
        for (int i = 1; i <= pageMaxNum; i++) {
            int pageSize = ASSET_DEFAULT_PAGE_SIZE;
            if (pageMaxNum == 1 || i == pageMaxNum) {
                pageSize = remainder;
            }

            List<SmsAssetFixedStorage> collect = initList.stream()
                    .skip((long) (i - 1) * ASSET_DEFAULT_PAGE_SIZE)
                    .limit(pageSize)
                    .collect(Collectors.toList());

            //遍历更新折旧数据
            for (SmsAssetFixedStorage fixedAsset : collect) {
                String asset_id = fixedAsset.getId();
                //开启事务
                DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
                // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
                dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                // 设置嵌套事务
                TransactionStatus status = transactionManager.getTransaction(dt);
                try {
                    //更新折旧数据
                    updateAssetDepreciation(asset_id, nowDate);

                    transactionManager.commit(status);
                } catch (Exception e) {
                    e.printStackTrace();
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_EXCEPTION;
                    createTaskDetail(task_id, REASON_UPDATE_ERR, asset_id);
                } finally {
                    if (status.isNewTransaction() && !status.isCompleted()) {
                        transactionManager.commit(status);
                        log.debug("++++++进来了");
                    }
                }
            }
        }
        SmsAssetFixedDepreciationTask smsImportTask = new SmsAssetFixedDepreciationTask();
        smsImportTask.setId(task_id);
        smsImportTask.setTaskStatus(task_finish_status);
        this.updateById(smsImportTask);
    }

    private void createTaskDetail(String task_id, String reason, String asset_id) {
        SmsAssetFixedDepreciationTaskDetail smsImportTaskDetail = new SmsAssetFixedDepreciationTaskDetail();
        smsImportTaskDetail.setTaskId(task_id);
        smsImportTaskDetail.setErrorDescription(reason);
        smsImportTaskDetail.setAssetId(asset_id);
        smsAssetFixedDepreciationTaskDetailMappers.insert(smsImportTaskDetail);
    }

    private void updateAssetDepreciation(String asset_id, Date nowDate) {
        SmsAssetFixedStorage smsAssetFixedStorage = smsAssetFixedStorageMapper.selectById(asset_id);
        //折旧月份
        int diffMonth = TimeUtil.GetDiffMonth(nowDate, smsAssetFixedStorage.getCreateTime());
        if (diffMonth > smsAssetFixedStorage.getAssetLifetime()) {
            return;
        }
        //最后一个月折旧价值
        //折旧价值
        BigDecimal depreciationPrice;
        if (diffMonth == smsAssetFixedStorage.getAssetLifetime()) {
            //最后一个月之前月份折旧总价
            BigDecimal otherDepreciationPrice = smsAssetFixedStorage.getAssetPerDepreciationPrice()
                    .multiply(new BigDecimal(diffMonth - 1));
            depreciationPrice = smsAssetFixedStorage.getAssetLastMonthDepreciationPrice()
                    .add(otherDepreciationPrice);
        } else {
            depreciationPrice = smsAssetFixedStorage.getAssetPerDepreciationPrice()
                    .multiply(new BigDecimal(diffMonth));
        }

        //剩余价值
        BigDecimal leftPrice = smsAssetFixedStorage.getAssetPrice().subtract(depreciationPrice);

        SmsAssetFixedStorage updateAsset = new SmsAssetFixedStorage();
        updateAsset.setId(asset_id);
        updateAsset.setAssetRealPrice(leftPrice);
        updateAsset.setAssetTotalDepreciationPrice(depreciationPrice);
        updateAsset.setAssetBuyMonth(diffMonth);
        smsAssetFixedStorageMapper.updateById(updateAsset);
    }


    @Override
    public ResponseResult getTaskInfoList(Integer pageNum, Integer pageSize) {
        Page<SmsAssetFixedDepreciationTask> page = new Page<>(pageNum, pageSize);
        smsAssetFixedDepreciationTaskMapper.selectPage(page, new QueryWrapper<SmsAssetFixedDepreciationTask>()
                .lambda()
                .orderByDesc(SmsAssetFixedDepreciationTask::getCreateTime));
        List<SmsAssetFixedDepreciationTaskResp> list = page.getRecords()
                .stream()
                .map(task -> {
                    SmsAssetFixedDepreciationTaskResp resp = new SmsAssetFixedDepreciationTaskResp();
                    BeanUtils.copyProperties(task, resp);

                    SmsUser smsUser = cacheUtil.getUserInfo(task.getCreateUserId());
                    SmsSearchUserResp userResp = new SmsSearchUserResp();
                    if (smsUser != null) {
                        BeanUtils.copyProperties(smsUser, userResp);
                        resp.setUserinfo(userResp);
                    }
                    return resp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(list, total);
    }

    @Override
    public ResponseResult getTaskDetailList(String taskId, Integer pageNum, Integer pageSize) {
        SmsAssetFixedDepreciationTask task = smsAssetFixedDepreciationTaskMapper.selectById(taskId);
        if (task == null){
            return CommonResult.failed(CommonCodeEnum.ASSET_DEPRECIATION_TASK_NOT_EXIST);
        }

        Page<SmsAssetFixedDepreciationTaskDetail> page = new Page<>(pageNum, pageSize);
        smsAssetFixedDepreciationTaskDetailMappers.selectPage(page, new QueryWrapper<SmsAssetFixedDepreciationTaskDetail>()
                .lambda()
                .eq(SmsAssetFixedDepreciationTaskDetail::getTaskId, taskId)
                .orderByDesc(SmsAssetFixedDepreciationTaskDetail::getCreateTime));
        List<SmsAssetFixedDepreciationTaskDetailResp> list = page.getRecords()
                .stream()
                .map(detail -> {
                    SmsAssetFixedDepreciationTaskDetailResp resp = new SmsAssetFixedDepreciationTaskDetailResp();
                    BeanUtils.copyProperties(detail, resp);
                    return resp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(list,total);
    }

    @Override
    public ResponseResult getAssetFixedDepreciationList() {
        return null;
    }
}
